package com.example.backblog.controller.front.fileupload;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.novelweb.tool.upload.local.pojo.UploadFileParam;
import com.example.backblog.annotation.UserIdParameter;
import com.example.backblog.constant.fileupload.SysConstant;
import com.example.backblog.dto.fileupload.AddFileDto;
import com.example.backblog.dto.fileupload.UploadFileDto;
import com.example.backblog.entity.fileupload.Files;
import com.example.backblog.exception.SystemException;
import com.example.backblog.repository.fileupload.FilesRepository;
import com.example.backblog.service.fileupload.FileService;
import com.example.backblog.util.EncodingUtils;
import com.example.backblog.util.ErrorCodeUtil;
import com.example.backblog.vo.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/file")
@Slf4j
public class FileController {

    @Autowired
    private  FileService fileService;
    @Autowired
    private FilesRepository filesRepository;



    /**
     * 断点续传完成后上传文件信息进行入库操作
     *
     * @param dto           dto
     * @param bindingResult 绑定的结果
     */
    @PostMapping("/add")
    public ApiResult<String> addFile(@UserIdParameter Long userId, @RequestBody AddFileDto dto, BindingResult bindingResult) {
        // 数据校验
        if (bindingResult.hasErrors()) {
            return ApiResult.error(ErrorCodeUtil.INVALID_PARAMETER,
                    bindingResult.getAllErrors().get(0).getDefaultMessage(),
                    null);
        }
        return fileService.addFile(dto,userId);
    }

    /**
     * 检查文件MD5（文件MD5若已存在进行秒传）
     *
     * @param md5      md5
     * @param fileName 文件名称
     */
    @GetMapping(value = "/check-file")
    public ApiResult<Object> checkFileMd5(@UserIdParameter Long userId, String md5, String fileName,Long parentId) {
        return fileService.checkFileMd5(md5, fileName,parentId,userId);
    }
    @GetMapping(value = "/breakpoint-upload")
    public ApiResult<Object> breakpointResumeUploadCheck(@UserIdParameter Long userId, UploadFileDto dto, HttpServletRequest request) {
        UploadFileParam param = new UploadFileParam();
        param.setFile(dto.getUpfile());
        param.setChunk(dto.getChunkNumber()-1);
        param.setChunks(dto.getTotalChunks());
        param.setName(dto.getFilename());
        param.setId("flag");
        param.setMd5("md5");
        return fileService.checkFileChunk(param,dto.getParentId(), request,userId);
    }
    /**
     * 断点续传方式上传文件：用于大文件上传
     *
     * @param dto   参数
     * @param request 请求
     */
    @PostMapping(value = "/breakpoint-upload", consumes = "multipart/*", headers = "content-type=multipart/form-data", produces = "application/json;charset=UTF-8")
    public ApiResult<Object> breakpointResumeUpload(@UserIdParameter Long userId, UploadFileDto dto, HttpServletRequest request) {
        UploadFileParam param = new UploadFileParam();
        param.setFile(dto.getUpfile());
        param.setChunk(dto.getChunkNumber()-1);
        param.setChunks(dto.getTotalChunks());
        param.setName(dto.getFilename());
        param.setId("flag");
        param.setMd5("md5");
        return fileService.breakpointResumeUpload(param, dto.getParentId(), request,userId);
    }

    /**
     * 图片/PDF查看
     *
     * @param id id
     * @return {@link ResponseEntity}<{@link byte[]}>
     * @throws IOException ioexception
     */
    @GetMapping(value = "/view/{id}", produces = MediaType.IMAGE_PNG_VALUE)
    public ResponseEntity<byte[]> viewFilesImage(@PathVariable Long id) throws IOException {
        ApiResult<Files> fileDetails = fileService.getFileDetails(id);
        if (!StrUtil.isEmpty(fileDetails.getData().getSuffix()) && !SysConstant.IMAGE_TYPE.contains(fileDetails.getData().getSuffix())) {
            throw new SystemException(ErrorCodeUtil.FILE_ERROR, "非图片/PDF类型请先下载");
        }
        InputStream inputStream = fileService.getFileInputStream(id);
        return new ResponseEntity<>(IoUtil.readBytes(inputStream), HttpStatus.OK);
    }

    /**
     * 文件下载
     *
     * @param id       id
     * @param isSource 是否使用原文件名
     * @param request  请求
     * @param response 响应
     */
    @GetMapping(value = "/download/{id}")
    public void viewFilesImage(@PathVariable Long id, @RequestParam(required = false) Boolean isSource, HttpServletRequest request, HttpServletResponse response) {
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            ApiResult<Files> fileDetails = fileService.getFileDetails(id);

            String filename = (isSource!=null && isSource) ? fileDetails.getData().getFileName() : fileDetails.getData().getFilePath();
            inputStream = fileService.getFileInputStream(id);
            response.setHeader("Content-Disposition", "attachment;filename=" + EncodingUtils.convertToFileName(request, filename));
            // 获取输出流
            outputStream = response.getOutputStream();
            IOUtils.copy(inputStream, outputStream);
        } catch (IOException e) {
            log.error("文件下载出错", e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 删除一个文件
     * @param id
     * @return
     */
    @DeleteMapping("/delete/id")
    public ApiResult deleteFile(Long id) throws Exception {
        fileService.deleteFile(id);
        return ApiResult.success();
    }

    /**
     * 文件下载
     * @param id
     * @param response
     * @throws Exception
     */
    @GetMapping("/download2/{id}")
    public void downloadFile(@PathVariable("id")Long id,HttpServletResponse response) throws Exception {
        this.fileService.download(id,response);
    }
    @CrossOrigin
    @GetMapping(value = "/view2/{id}.doc")
    public void viewFilesImage2(@PathVariable Long id,HttpServletResponse response) throws Exception {
       fileService.viewMedia(id,response);
    }

    @GetMapping("/back/parent")
    public ApiResult obtainParent(Long parent){
        Optional<Files> byId = this.filesRepository.findById(parent);
        if (byId.isPresent()) {
            Files files = byId.get();
            Long parentId = files.getParentId();
            return ApiResult.success(parentId);
        }else {
            return ApiResult.success();
        }
    }
}
